home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / midi / gfft.lha / gfft-2.03 / source / gfft-2.03-source.lha / calibrat.c < prev    next >
C/C++ Source or Header  |  1996-01-02  |  7KB  |  298 lines

  1. /***************************************************************************
  2.  *          Copyright (C) 1994  Charles P. Peterson                  *
  3.  *         4007 Enchanted Sun, San Antonio, Texas 78244-1254             *
  4.  *              Email: Charles_P_Peterson@fcircus.sat.tx.us                *
  5.  *                                                                         *
  6.  *          This is free software with NO WARRANTY.                  *
  7.  *          See gfft.c, or run program itself, for details.              *
  8.  *              Support is available for a fee.                      *
  9.  ***************************************************************************
  10.  *
  11.  * Program:     gfft--General FFT analysis
  12.  * File:        calibrat.c
  13.  * Purpose:     calibration(s) 
  14.  * Author:      Charles Peterson (CPP)
  15.  * History:     15-March-1994 CPP; Created.
  16.  *              5-Aug-94 CPP (1.05); add new calibrations to end of list
  17.  * Comment:     Simple 'relative' calibration with linear interpolation.
  18.  *              Any number of calibration(s) may be in effect.
  19.  *              NOT complex deconvolution (maybe in a few years).
  20.  *              Linear interpolation, and flat extension are used
  21.  *              (Flat extension helps with fuzzy endpoints).
  22.  */
  23.  
  24. #include <stdio.h>
  25. #include <stdlib.h>  /* strtod */
  26. #include <string.h>  /* strtok */
  27. #include <math.h>    /* log10, pow */
  28.  
  29. #include "gfft.h"
  30. #include "settings.h"
  31. #include "wbench.h"
  32.  
  33. #define CAL_BUFSIZ 133
  34. #define PROGRESS_INCREMENT 128
  35.  
  36. int calibration_list__count (struct cal_st **clistp)
  37. {
  38.     int count = 0;
  39.     struct cal_st *clist = *clistp;
  40.  
  41.     while (clist)
  42.     {
  43.     count++;
  44.     clist = clist->next;
  45.     }
  46.     return count;
  47. }
  48.  
  49.  
  50. void calibration_list__cancel (struct cal_st **clistp)
  51. {
  52.     struct cal_st *clist = *clistp;
  53. /*
  54.  * Free tail of list recursively, then free this node
  55.  */
  56.     if (clist)
  57.     {
  58.     if (clist->next)
  59.     {
  60.         calibration_list__cancel (&clist->next);
  61.     }
  62.     gfree (clist->frequencies);
  63.     gfree (clist->amplitudes);
  64. /*    gfree (clist->filename); potentially dangerous */
  65.     gfree (clist);
  66.     }
  67.     *clistp = NULL;
  68. }
  69.  
  70.  
  71. void calibration_list__add (struct cal_st **clistp,
  72.                 char *cname, 
  73.                 FILE *cfile,
  74.                 BOOLEAN db_scale)
  75. {
  76.     int progress_count = 0;
  77.     struct cal_st *clist = *clistp;
  78.     char cal_buf[CAL_BUFSIZ];
  79.     char *token;
  80.     char *beyondpointer;
  81.     double *freq_array = NULL;
  82.     float *ampl_array = NULL;
  83.     double frequency;
  84.     float amplitude;
  85.     long size = 0;
  86.     struct cal_st *new_cal;
  87. /*
  88.  * First, read in file data
  89.  */
  90.     while (fgets (cal_buf, CAL_BUFSIZ, cfile))
  91.     {
  92.     if (progress_count++ % PROGRESS_INCREMENT == 0)
  93.     {
  94.         progress_requester__update (-1);
  95.     }
  96.     /*
  97.      * Skip over comment lines
  98.      */
  99.     if (cal_buf[0] == '#' || cal_buf[0] == ';' || cal_buf[0] == '!')
  100.     {
  101.         continue;
  102.     }
  103.     /*
  104.      * get frequency value
  105.      */
  106.     token = strtok (cal_buf, " ");
  107.     if (!token)
  108.     {
  109.         error_message (INVALID_CALIBRATION_FILE);
  110.         RAISE_ERROR (NOTHING_SPECIAL);    /* longjmp outa here */
  111.     }
  112.     frequency = strtod (token, &beyondpointer);
  113.     if (*beyondpointer != '\0')
  114.     {
  115.         error_message (INVALID_CALIBRATION_FILE);
  116.         RAISE_ERROR (NOTHING_SPECIAL);    /* longjmp outa here */
  117.     }
  118.     token = strtok (NULL, " ");
  119.     if (!token)
  120.     {
  121.         error_message (INVALID_CALIBRATION_FILE);
  122.         RAISE_ERROR (NOTHING_SPECIAL);    /* longjmp outa here */
  123.     }
  124.     amplitude = (float) strtod (token, &beyondpointer);
  125.     if (*beyondpointer != '\0' && *beyondpointer != '\n')
  126.     {
  127.         error_message (INVALID_CALIBRATION_FILE);
  128.         RAISE_ERROR (NOTHING_SPECIAL);    /* longjmp outa here */
  129.     }
  130.     /*
  131.      * Add new values to arrays
  132.      */
  133.     size++;
  134.     freq_array = grealloc (freq_array, (size * sizeof frequency), 
  135.                    NOTHING_SPECIAL);
  136.     ampl_array = grealloc (ampl_array, (size * sizeof amplitude), 
  137.                    NOTHING_SPECIAL);
  138.     freq_array[size-1] = frequency;
  139.     ampl_array[size-1] = amplitude;
  140.     }
  141.     if (size <= 0)
  142.     {
  143.     error_message (INVALID_CALIBRATION_FILE);
  144.     RAISE_ERROR (NOTHING_SPECIAL);    /* longjmp outa here */
  145.     }
  146.  
  147. /*
  148.  * create new node
  149.  */
  150.     new_cal = gmalloc (sizeof (struct cal_st), NOTHING_SPECIAL);
  151.     new_cal->next = NULL;
  152.     new_cal->filename = cname;
  153.     new_cal->size = size;
  154.     new_cal->db = db_scale;
  155.     new_cal->frequencies = freq_array;
  156.     new_cal->amplitudes = ampl_array;
  157.     new_cal->index = 0;
  158. /*
  159.  * insert new node in list, or at start
  160.  */
  161.     if (clist)
  162.     {
  163.     while (clist->next)
  164.     {
  165.         clist = clist->next;
  166.     }
  167.     clist->next = new_cal;
  168.     }
  169.     else
  170.     {
  171.     *clistp = new_cal;
  172.     }
  173. }
  174.  
  175. void calibration_list__reset (struct cal_st **clistp)
  176. {
  177.     if (*clistp)
  178.     {
  179.     (*clistp)->index = 0;
  180.     calibration_list__reset (&((*clistp)->next));
  181.     }
  182. }
  183.  
  184. void calibration_list__write (FILE *fp, char *cstr, struct cal_st **clistp)
  185. {
  186.     struct cal_st *clist = *clistp;
  187.  
  188.     while (clist)
  189.     {
  190.     if (clist->db)
  191.     {
  192.         fprintf (fp, "%sDBCalibrate %s\n", cstr, clist->filename);
  193.     }
  194.     else
  195.     {
  196.         fprintf (fp, "%sCalibrate %s\n", cstr, clist->filename);
  197.     }
  198.     clist = clist->next;
  199.     }
  200. }
  201.  
  202.  
  203. float calibration_list__apply (struct cal_st **clistp,
  204.                    float value, double frequency)
  205. {
  206.     struct cal_st *clist = *clistp;
  207.     long index;
  208.     BOOLEAN outrange = TRUE;
  209.     double factor;
  210.  
  211. /*
  212.  * Assumption is made that frequencies are applied in an increasing
  213.  * order.  When starting over, call calibration_list__reset
  214.  *
  215.  * Make local copy of 'index'
  216.  */
  217.     index = clist->index;
  218. /*
  219.  * Find applicable index
  220.  */
  221.     while (frequency > clist->frequencies[index])
  222.     {
  223.     outrange = FALSE;
  224.     if (++index >= clist->size)
  225.     {
  226.         index--;
  227.         outrange = TRUE;
  228.         break;
  229.     }
  230.     }
  231.     clist->index = index;  /* update */
  232.     
  233. /*
  234.  * Compute the factor to use
  235.  */
  236.  
  237.     if (frequency == clist->frequencies[index] || outrange)
  238.     {
  239.     factor = clist->amplitudes[index];
  240.     }
  241.     else
  242.     {
  243.     /*
  244.      * linear interpolation is fun
  245.      * (Sorry I don't bother with anything more sophisticated yet)
  246.      */
  247.     double x1 = clist->frequencies[index-1];
  248.     double x2 = clist->frequencies[index];
  249.     double y1 = clist->amplitudes[index-1];
  250.     double y2 = clist->amplitudes[index];
  251.     double slope = (y2 - y1) / (x2 - x1);
  252.     double offset = y1 - (slope * x1);
  253.  
  254.     factor = (slope * frequency) + offset;
  255.     }
  256.  
  257. /*
  258.  * Apply
  259.  */
  260.     if (Db)
  261.     {
  262.     if (clist->db)
  263.     {
  264.         value -= factor;
  265.     }
  266.     else
  267.     {
  268.         double dbfactor;
  269.         if (factor <= 0.0) RAISE_ERROR (NOTHING_SPECIAL);
  270.         dbfactor = 20.0 * log10 (factor);
  271.         value -= dbfactor;
  272.     }
  273.     }
  274.     else
  275.     {
  276.     if (!clist->db)
  277.     {
  278.         if (factor == 0.0) RAISE_ERROR (NOTHING_SPECIAL);
  279.         value /= factor;
  280.     }
  281.     else
  282.     {
  283.         value /= pow (10.0, (factor * 0.05));
  284.     }
  285.     }
  286. /*
  287.  * Do next calibration in list
  288.  */
  289.     if (clist->next)
  290.     {
  291.     value = calibration_list__apply (&clist->next, value, frequency);
  292.     }
  293.  
  294.     return value;
  295. }
  296.     
  297.  
  298.